﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace ICSharpCode.WinFormsUI.Controls.Chart3D
{
    public class SmoothCurve3D : Shape3D
    {
        private Point3D[] points = null;
        public Point3D[] Points
        {
            get { return points; }
            set
            {
                points = value;
                Maxnum(points);
                if (control != null && invalidateable)
                    control.Invalidate();
            }
        }
              
        internal SmoothCurve3D(System.Windows.Forms.Control control, Camera camera, Coordinate3D coordinate)
        {
            this.camera = camera;
            this.control = control;
            this.coordinate = coordinate;
        }

        public override void Draw(System.Drawing.Graphics g)
        {
            if (camera == null) return;
            if (points == null) return;

            var _SmoothingMode = g.SmoothingMode;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            DrawLines(g);
            //DrawSelectedPoint3d(g);    

            g.SmoothingMode = _SmoothingMode;
        }

        protected void DrawLines(Graphics g)
        {
            g.DrawLines(new Pen(lineColor, lineWidth), camera.ToArrayPointF(Convert.ToVertexs(coordinate, points)));
            if (_dashStyleIsVisable)
            {
                Point2D[] pts2d = camera.GetProjection(Convert.ToVertexs(coordinate, points));
                using (var bru = new SolidBrush(_dashStyleColor))
                {
                    for (int i = 0; i < pts2d.Length; i++)
                    {
                        g.FillEllipse(bru, pts2d[i].X - _dashStyleSize, pts2d[i].Y - _dashStyleSize, 2 * _dashStyleSize, 2 * _dashStyleSize);
                    }
                }
            }
        }

        protected void DrawSelectedPoint3d(Graphics g)
        {
            if (SelectedPoint3d != null)
            {
                float _selectedDashStyleSize = _dashStyleSize + 2;
                Point2D pt2d = camera.GetProjection(Convert.ToVertex(coordinate, SelectedPoint3d));
                g.FillEllipse(new SolidBrush(_selectedDashStyleColor), pt2d.X - _selectedDashStyleSize, pt2d.Y - _selectedDashStyleSize, 2 * _selectedDashStyleSize, 2 * _selectedDashStyleSize);
                string ToShowValues = string.Format(CursorValueFormat.Replace("{name}", this.Name), SelectedPoint3d.X.ToString("F2"), SelectedPoint3d.Y.ToString("F2"), SelectedPoint3d.Z.ToString("F2"));
                SizeF labelSize = g.MeasureString(ToShowValues, this.control.Font);
                g.DrawString(ToShowValues, control.Font, Brushes.Blue, control.Width - labelSize.Width - 6, 10);
            }
        }

        public override void Maxnum(Point3D[] points)
        {
            base.Maxnum(points);
        }

        public override bool FindNestPoint(Point point, out Point3D result)
        {
            this.SelectedPoint3d = result = null;
            if (this.points != null)
            {
                IDictionary<int, Point2D> nearPoints = new Dictionary<int, Point2D>();
                if (this.points.Length > 0)
                {
                    for (int i = 0; i < this.points.Length; i++)
                    {
                        var p = this.camera.Transform2D(Convert.ToVertex(this.coordinate, this.Points[i]));
                        if (new RectangleF(p.X - _dashStyleSize, p.Y - _dashStyleSize, 2 * _dashStyleSize, 2 * _dashStyleSize).Contains(point))
                        {
                            p.Module = (float)(Math.Pow((double)p.X - point.X, 2) + Math.Pow((double)p.Y - point.Y, 2));
                            if (p.Module < 0.7)
                            {
                                result = this.points[i];
                                return true;
                            }
                            nearPoints.Add(i, p);
                        }
                    }
                }
                if (nearPoints.Count > 0)
                {
                    var z = nearPoints.Where(w => w.Value.Module == nearPoints.Min(o => o.Value.Module)).FirstOrDefault();
                    result = this.points[z.Key];
                    return true;
                }
            }        
            return false;
        }

    }
}
